package com.jc.order.util;

import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通用Java对象比较工具类
 */
public class DTOCompareUtil {

    /**
     * 字段描述注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface FieldDesc {
        String value() default "";
    }

    /**
     * 忽略比较注解
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface IgnoreCompare {
    }

    /**
     * 字段变更记录
     */
    public static class FieldChange {
        private final String fieldName;
        private final String fieldDescription;
        private final Object oldValue;
        private final Object newValue;

        public FieldChange(String fieldName, String fieldDescription,
                           Object oldValue, Object newValue) {
            this.fieldName = fieldName;
            this.fieldDescription = fieldDescription;
            this.oldValue = oldValue;
            this.newValue = newValue;
        }

        public String getFieldName() {
            return fieldName;
        }

        public String getFieldDescription() {
            return fieldDescription;
        }

        public Object getOldValue() {
            return oldValue;
        }

        public Object getNewValue() {
            return newValue;
        }

        @Override
        public String toString() {
            return String.format("%s(%s): [%s] 改为 [%s]",
                    fieldDescription, fieldName,
                    formatValue(oldValue),
                    formatValue(newValue));
        }

        private String formatValue(Object value) {
            if (value == null) return "无";
            return value.toString();
        }
    }

    // 缓存类字段信息，提高性能
    private static final Map<Class<?>, Map<String, String>> FIELD_DESC_CACHE = new ConcurrentHashMap<>(64);
    private static final Set<Class<?>> WRAPPER_TYPES = new HashSet<>(Arrays.asList(
            Boolean.class, Character.class, Byte.class, Short.class,
            Integer.class, Long.class, Float.class, Double.class, Void.class
    ));

    public static List<FieldChange> compareObjectChanges(Object oldObj, Object newObj) {
        if (oldObj == null || newObj == null) {
            return Collections.emptyList();
        }

        Class<?> clazz = oldObj.getClass();
        if (!clazz.equals(newObj.getClass())) {
            throw new IllegalArgumentException("比较对象类型不一致: " + clazz + " vs " + newObj.getClass());
        }

        try {
            Map<String, String> fieldDescriptions = FIELD_DESC_CACHE.computeIfAbsent(
                    clazz, k -> buildFieldDescriptionMap(clazz)
            );

            List<FieldChange> changes = new ArrayList<>(16);
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                if (shouldSkipField(field)) {
                    continue;
                }

                field.setAccessible(true);
                Object oldValue = field.get(oldObj);
                Object newValue = field.get(newObj);

                if (!isEqual(oldValue, newValue)) {
                    String fieldDesc = fieldDescriptions.get(field.getName());
                    changes.add(new FieldChange(
                            field.getName(),
                            fieldDesc != null ? fieldDesc : field.getName(),
                            oldValue,
                            newValue
                    ));
                }
            }
            return changes;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("字段访问失败", e);
        }
    }

    private static boolean shouldSkipField(Field field) {
        int modifiers = field.getModifiers();
        return Modifier.isStatic(modifiers) ||
               field.isAnnotationPresent(IgnoreCompare.class) ||
               Modifier.isTransient(modifiers);
    }

    private static boolean isEqual(Object oldValue, Object newValue) {
        if (oldValue == newValue) {
            return true;
        }
        if (oldValue == null || newValue == null) {
            return false;
        }

        // 处理基础类型和包装类
        if (isWrapperType(oldValue.getClass()) || oldValue.getClass().isPrimitive()) {
            return oldValue.equals(newValue);
        }

        // 特殊类型处理
        if (oldValue instanceof BigDecimal && newValue instanceof BigDecimal) {
            return ((BigDecimal) oldValue).compareTo((BigDecimal) newValue) == 0;
        }
        if (oldValue instanceof Date && newValue instanceof Date) {
            return ((Date) oldValue).getTime() == ((Date) newValue).getTime();
        }

        return oldValue.equals(newValue);
    }

    private static boolean isWrapperType(Class<?> clazz) {
        return WRAPPER_TYPES.contains(clazz);
    }

    /**
     * 构建字段描述映射
     */
    private static Map<String, String> buildFieldDescriptionMap(Class<?> clazz) {
        Map<String, String> descriptions = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            String fieldName = field.getName();

            // 优先使用注解中的描述
            if (field.isAnnotationPresent(FieldDesc.class)) {
                FieldDesc annotation = field.getAnnotation(FieldDesc.class);
                descriptions.put(fieldName, annotation.value());
            }
            // 其次使用JavaDoc中的描述
            else {
                // 这里可以扩展为从JavaDoc获取描述，但需要额外依赖
                // 目前简单处理为使用字段名
                descriptions.put(fieldName, fieldName);
            }
        }

        return descriptions;
    }
}